package com.gitee.chippyer.logger.repository;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gitee.chippyer.logger.compontents.LogRepositoryCommonComponent;
import com.gitee.chippyer.logger.engine.bo.LogEntryBO;
import com.gitee.chippyer.logger.repository.ability.mapper.LogEntryMapper;
import com.gitee.chippyer.logger.repository.ability.po.LogEntry;
import com.gitee.chippyer.logger.repository.bo.PageInfoBO;
import com.gitee.chippyer.logger.repository.bo.QueryLogPageParamBO;
import com.gitee.chippyer.logger.repository.converter.LogRepositoryConverter;
import com.gitee.chippyer.logger.utils.ObjectUtil;

import java.sql.Timestamp;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

class MysqlLogStoreRepositoryImpl extends ServiceImpl<LogEntryMapper, LogEntry> implements LogStoreRepository {

    private final LogRepositoryCommonComponent logRepositoryCommonComponent;

    public MysqlLogStoreRepositoryImpl(LogRepositoryCommonComponent logRepositoryCommonComponent) {
        this.logRepositoryCommonComponent = logRepositoryCommonComponent;
    }

    @Override
    public void batchCreation(Collection<LogEntryBO> logEntryBOList) {
        final List<LogEntry> logEntryList = logEntryBOList.stream()
                .map(this::toLogEntry)
                .collect(Collectors.toList());

        super.saveBatch(logEntryList, logEntryList.size());
    }

    @Override
    public void creation(LogEntryBO logEntryBO) {
        super.save(this.toLogEntry(logEntryBO));
    }

    @Override
    public PageInfoBO<LogEntryBO> getPage(QueryLogPageParamBO queryLogPageParam) {
        final int pageNum = queryLogPageParam.getPageNum();
        final int pageSize = queryLogPageParam.getPageSize();
        logRepositoryCommonComponent.validatePageParam(pageNum, pageSize);

        final String tId = queryLogPageParam.getTId();
        final Date startDateTime = queryLogPageParam.getStartDateTime();
        final Date endDateTime = queryLogPageParam.getEndDateTime();

        if (ObjectUtil.isEmpty(tId) && (ObjectUtil.isEmpty(startDateTime) || ObjectUtil.isEmpty(endDateTime))) {
            throw new IllegalArgumentException("[tId], [startDateTime, endDateTime]至少要有一组参数不为空");
        }

        final IPage<LogEntry> page = new Page<>(pageNum, pageSize);

        final LambdaQueryWrapper<LogEntry> wrapper = new LambdaQueryWrapper<>();

        if (ObjectUtil.isNotEmpty(tId)) {
            wrapper.eq(LogEntry::getTId, tId);
        }

        if (ObjectUtil.isNotEmpty(startDateTime) && ObjectUtil.isNotEmpty(endDateTime)) {
            wrapper.between(LogEntry::getCreateTime, startDateTime, endDateTime);
        }

        if (ObjectUtil.isNotEmpty(queryLogPageParam.getMsg())) {
            wrapper.like(LogEntry::getMsg, queryLogPageParam.getMsg());
        }

        if (ObjectUtil.isNotEmpty(queryLogPageParam.getLevel())) {
            wrapper.eq(LogEntry::getLevel, queryLogPageParam.getLevel());
        }

        wrapper.orderByDesc(LogEntry::getCreateTime);

        final IPage<LogEntry> pageInfo = super.page(page, wrapper);

        final List<LogEntry> logEntryList = pageInfo.getRecords();
        if (ObjectUtil.isEmpty(logEntryList)) {
            return new PageInfoBO<>();
        }

        final List<LogEntryBO> logEntryBOList = logEntryList.stream()
                .map(this::toLogEntryBO)
                .collect(Collectors.toList());
        return new PageInfoBO<>(pageInfo.getTotal(), logEntryBOList, pageInfo.getPages());
    }

    @Override
    public void batchRemove(Date limitDateTime) {
        final LambdaQueryWrapper<LogEntry> wrapper = new LambdaQueryWrapper<>();
        wrapper.le(LogEntry::getCreateTime, limitDateTime);

        super.remove(wrapper);
    }

    private LogEntry toLogEntry(LogEntryBO logEntryBO) {
        final LogEntry logEntry = LogRepositoryConverter.INSTANCE.toLogEntry(logEntryBO);

        final Date createTime = logEntryBO.getCreateTime();
        if (ObjectUtil.isNotEmpty(createTime)) {
            logEntry.setCreateTime(new Timestamp(createTime.getTime()));
        }

        return logEntry;
    }

    private LogEntryBO toLogEntryBO(LogEntry logEntry) {
        final LogEntryBO logEntryBO = LogRepositoryConverter.INSTANCE.toLogEntryBO(logEntry);
        final Timestamp createTime = logEntry.getCreateTime();
        if (ObjectUtil.isNotEmpty(createTime)) {
            logEntryBO.setCreateTime(new Date(createTime.getTime()));
        }
        return logEntryBO;
    }

}
